package com.sjd.mall.service.account.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.PageHelper;
import com.sjd.common.constant.GoldenBeanConstants;
import com.sjd.common.core.domain.AjaxResult;
import com.sjd.common.utils.DateUtils;
import com.sjd.common.utils.OrderNoUtils;
import com.sjd.mall.domain.SjdAccountDO;
import com.sjd.mall.domain.SjdAccountGlodenBeanDetailsDO;
import com.sjd.mall.domain.dto.account.BasePageHelperDTO;
import com.sjd.mall.mapper.SjdAccountGlodenBeanDetailsMapper;
import com.sjd.mall.domain.dto.account.AccountRechargeQueryResponseDTO;
import com.sjd.mall.domain.dto.account.AccountRechargeRequestDTO;
import com.sjd.mall.mapper.SjdAccountMapper;
import com.sjd.mall.service.account.AccountService;
import com.sjd.mall.service.account.AccountGoldenBeanService;
import com.sjd.mall.domain.dto.account.CreateRechargeOrderRequestDTO;
import com.sjd.wx.config.WxMaProperties;
import com.sjd.wx.config.WxPayConfiguration;
import com.sjd.wx.utils.ThirdSessionHolder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

import static java.lang.Math.abs;

/**
 * @ProjectName: sjd
 * @Package: com.sjd.mall.service.account.impl
 * @ClassName: RechargeOrderServiceImpl
 * @Author: genglong
 * @Description: 金豆操作实现类
 * @Date: 2022/1/12 15:54
 * @Version: 1.0
 */
@Service
@AllArgsConstructor
@Slf4j
public class AccountGoldenBeanServiceImpl implements AccountGoldenBeanService {

    private final SjdAccountGlodenBeanDetailsMapper sjdAccountGlodenBeanDetailsMapper;

    private final SjdAccountMapper sjdAccountMapper;

    private final AccountService accountService;

    private final WxMaProperties properties;

    @Override
    public SjdAccountGlodenBeanDetailsDO createOrder(CreateRechargeOrderRequestDTO requestDTO) {
        //订单号生成
        String orderNo = OrderNoUtils.generateOrderNo(OrderNoUtils.OrderType.BILL_RECHARGE);
        Integer goldenNum = requestDTO.getRechargeAmount().intValue() * 10;
        SjdAccountGlodenBeanDetailsDO sjdAccountGlodenBeanDetailsDO = SjdAccountGlodenBeanDetailsDO.builder()
                .accountId(ThirdSessionHolder.getThirdSession().getAccountId()).memberId(ThirdSessionHolder.getThirdSession().getMemberId())
                .orderType(GoldenBeanConstants.RECHARGE).status(GoldenBeanConstants.ORDER_CREATE).goldenBeanNum(goldenNum)
                .orderNo(orderNo).amount(requestDTO.getOrderAmount()).actualAmount(requestDTO.getRechargeAmount())
                .discountAmount(requestDTO.getDiscountAmount()).remark("金豆充值，实付金额"+requestDTO.getRechargeAmount()+"元").createTime(new Date()).modifyTime(new Date()).build();
        sjdAccountGlodenBeanDetailsMapper.insertSelective(sjdAccountGlodenBeanDetailsDO);
        return sjdAccountGlodenBeanDetailsDO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult createConsumeOrRefoundOrder(String orderType,Integer goldenBeanNum,String remark) {
        SjdAccountDO sjdAccountDO = sjdAccountMapper.findAccountByMemberId(ThirdSessionHolder.getSjdMemberId());
        if (ObjectUtil.isEmpty(sjdAccountDO)){
            return AjaxResult.error("账户信息不存在");
        }
        //消费
        if(GoldenBeanConstants.CONSUME_CROPS.equals(orderType)||GoldenBeanConstants.CONSUME_FARM_TOOLS.equals(orderType)||
                GoldenBeanConstants.CONSUME_COURSE.equals(orderType)||GoldenBeanConstants.CONSUME_LAND.equals(orderType)||
                GoldenBeanConstants.CONSUME_SEED.equals(orderType)){
            if (goldenBeanNum>sjdAccountDO.getGoldenNum()){
                return AjaxResult.error("金豆不足！");
            }
            //修改账户金豆数量
            sjdAccountMapper.updateByPrimaryKeySelective(SjdAccountDO.builder().id(sjdAccountDO.getId()).goldenNum(sjdAccountDO.getGoldenNum()-goldenBeanNum)
            .modifyTime(new Date()).build());
            String orderNo = OrderNoUtils.generateOrderNo(OrderNoUtils.OrderType.BILL_CONSUME);
            SjdAccountGlodenBeanDetailsDO sjdAccountGlodenBeanDetailsDO = SjdAccountGlodenBeanDetailsDO.builder()
                    .accountId(ThirdSessionHolder.getThirdSession().getAccountId()).memberId(ThirdSessionHolder.getThirdSession().getMemberId())
                    .orderType(orderType).status(GoldenBeanConstants.ORDER_CONSUME_SUCESS).goldenBeanNum(goldenBeanNum).remark(remark)
                    .orderNo(orderNo).orderConsumeTime(DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS)).createTime(new Date()).modifyTime(new Date()).build();
            sjdAccountGlodenBeanDetailsMapper.insertSelective(sjdAccountGlodenBeanDetailsDO);
        }
        if(GoldenBeanConstants.REFOUND.equals(orderType)){
            //修改账户金豆数量
            sjdAccountMapper.updateByPrimaryKeySelective(SjdAccountDO.builder().id(sjdAccountDO.getId()).goldenNum(sjdAccountDO.getGoldenNum()+goldenBeanNum)
                    .modifyTime(new Date()).build());
            String orderNo = OrderNoUtils.generateOrderNo(OrderNoUtils.OrderType.BILL_REFOUND);
            SjdAccountGlodenBeanDetailsDO sjdAccountGlodenBeanDetailsDO = SjdAccountGlodenBeanDetailsDO.builder()
                    .accountId(ThirdSessionHolder.getThirdSession().getAccountId()).memberId(ThirdSessionHolder.getThirdSession().getMemberId())
                    .orderType(GoldenBeanConstants.REFOUND).status(GoldenBeanConstants.ORDER_REFOUND_SUCESS).goldenBeanNum(goldenBeanNum).remark(remark)
                    .orderNo(orderNo).orderConsumeTime(DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS)).createTime(new Date()).modifyTime(new Date()).build();
            sjdAccountGlodenBeanDetailsMapper.insertSelective(sjdAccountGlodenBeanDetailsDO);
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult recharge(AccountRechargeRequestDTO requestDTO) {
        SjdAccountGlodenBeanDetailsDO consumeDO = sjdAccountGlodenBeanDetailsMapper.selectByPrimaryKey(requestDTO.getOrderNo());
        if (null == consumeDO) {
            return AjaxResult.error("订单不存在！");
        }
        if (!GoldenBeanConstants.ORDER_CREATE.equals(consumeDO.getStatus())) {
            return AjaxResult.error("订单状态不允许支付！");
        }
        //组装JSAPI请求参数
        WxPayUnifiedOrderV3Request orderV3Request = new WxPayUnifiedOrderV3Request();
        orderV3Request.setAppid(properties.getConfigs().get(0).getAppId());
        orderV3Request.setMchid(properties.getConfigs().get(0).getMchId());
        orderV3Request.setDescription("账户充值，购买金豆");
        orderV3Request.setOutTradeNo(requestDTO.getOrderNo());
        //TODO 回调地址需要配置
        orderV3Request.setNotifyUrl(GoldenBeanConstants.NOTIFY_URL);
        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
        amount.setTotal(BaseWxPayRequest.yuanToFen(consumeDO.getActualAmount().toString()));
        orderV3Request.setAmount(amount);
        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
        payer.setOpenid(ThirdSessionHolder.getThirdSession().getOpenId());
        orderV3Request.setPayer(payer);
        WxPayService wxPayService = WxPayConfiguration.getPayService();
        WxPayUnifiedOrderV3Result.JsapiResult jsapiResult;
        try {
            jsapiResult = wxPayService.createOrderV3(TradeTypeEnum.JSAPI,orderV3Request);
        } catch (WxPayException e) {
            e.printStackTrace();
            return AjaxResult.error("订单支付异常");
        }
        return AjaxResult.success(jsapiResult);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String payResultNotify(HttpServletRequest request) {
        Map<String,String> resultMap = new HashMap<>(2);
        SignatureHeader header = new SignatureHeader();
        header.setNonce(request.getHeader("Wechatpay-Nonce"));
        header.setSerial(request.getHeader("Wechatpay-Serial"));
        header.setSignature(request.getHeader("Wechatpay-Signature"));
        header.setTimeStamp(request.getHeader("Wechatpay-Signature"));
        try {
            String notifyData = getRequestBody(request);
            WxPayService wxPayService = WxPayConfiguration.getPayService();
            WxPayRefundNotifyV3Result wxPayRefundNotifyV3Result = wxPayService.parseRefundNotifyV3Result(notifyData,header);
            SjdAccountGlodenBeanDetailsDO consumeDO = sjdAccountGlodenBeanDetailsMapper.selectByPrimaryKey(wxPayRefundNotifyV3Result.getResult().getOutTradeNo());
            if (ObjectUtil.isEmpty(consumeDO)){
                resultMap.put("code","FAIL");
                resultMap.put("message","系统错误");
                log.error("充值订单不存在");
                return JSONObject.toJSONString(resultMap);
            }
            SjdAccountGlodenBeanDetailsDO rechargeConsumeDO = SjdAccountGlodenBeanDetailsDO.builder().orderNo(consumeDO.getOrderNo()).build();
            if("TRANSACTION.SUCCESS".equals(wxPayRefundNotifyV3Result.getRawData().getEventType())){
                //支付成功的逻辑,修改订单状态为成功
                rechargeConsumeDO.setTransactionId(wxPayRefundNotifyV3Result.getResult().getTransactionId());
                rechargeConsumeDO.setStatus(GoldenBeanConstants.ORDER_RECHARGE_SUCCESS);
                rechargeConsumeDO.setOrderRechargeTime(wxPayRefundNotifyV3Result.getResult().getSuccessTime());
                rechargeConsumeDO.setModifyTime(new Date());
                sjdAccountGlodenBeanDetailsMapper.updateByPrimaryKeySelective(rechargeConsumeDO);
                //修改账户的金豆数量
                SjdAccountDO sjdAccountDO = accountService.findAccountByMemberId(ThirdSessionHolder.getSjdMemberId());
                Integer goldenNum = sjdAccountDO.getGoldenNum() + rechargeConsumeDO.getGoldenBeanNum();
                SjdAccountDO newAccountDO = SjdAccountDO.builder().id(sjdAccountDO.getId()).goldenNum(goldenNum)
                        .modifyTime(new Date()).build();
                sjdAccountMapper.updateByPrimaryKeySelective(newAccountDO);
            }{
                //修改订单状态为失败
                rechargeConsumeDO.setStatus(GoldenBeanConstants.ORDER_RECHARGE_FAIL);
                sjdAccountGlodenBeanDetailsMapper.updateByPrimaryKeySelective(rechargeConsumeDO);
            }
            resultMap.put("code","SUCESS");
            resultMap.put("message","");
            return JSONObject.toJSONString(resultMap);
        } catch (WxPayException  e) {
            e.printStackTrace();
        }
        resultMap.put("code","FAIL");
        resultMap.put("message","系统错误");
        log.error("支付回调异常");
        return JSONObject.toJSONString(resultMap);
    }

    @Override
    public List<AccountRechargeQueryResponseDTO> queryGoldenBeanOderList() {
        List<SjdAccountGlodenBeanDetailsDO> list = sjdAccountGlodenBeanDetailsMapper.queryGoldenBeanOrderList(ThirdSessionHolder.getThirdSession().getAccountId());
        List<AccountRechargeQueryResponseDTO> resultList = new ArrayList<>();
        for(SjdAccountGlodenBeanDetailsDO rechargeOrderDO : list){
            AccountRechargeQueryResponseDTO responseDTO = AccountRechargeQueryResponseDTO.builder()
                    .orderNo(rechargeOrderDO.getOrderNo())
                    .orderType(rechargeOrderDO.getOrderType())
                    .status(rechargeOrderDO.getStatus())
                    .goldenBeanNum(rechargeOrderDO.getGoldenBeanNum())
                    .createTime(rechargeOrderDO.getCreateTime()).build();
            if (GoldenBeanConstants.RECHARGE.equals(rechargeOrderDO.getOrderType()) && GoldenBeanConstants.ORDER_RECHARGE_SUCCESS.equals(rechargeOrderDO.getStatus())) {
                responseDTO.setRechargeTime(rechargeOrderDO.getOrderRechargeTime());
                responseDTO.setAmount(rechargeOrderDO.getAmount());
                responseDTO.setActualAmount(rechargeOrderDO.getActualAmount());
                responseDTO.setDiscountAmount(rechargeOrderDO.getDiscountAmount());
            }else if (GoldenBeanConstants.REFOUND.equals(rechargeOrderDO.getOrderType()) && GoldenBeanConstants.ORDER_CONSUME_SUCESS.equals(rechargeOrderDO.getStatus())) {
                responseDTO.setRefoundTime(rechargeOrderDO.getOrderRefoundTime());
            }else{
                responseDTO.setConsumeTime(rechargeOrderDO.getOrderConsumeTime());
            }
            resultList.add(responseDTO);
        }
        return resultList;
    }

    /**
     * 获取请求文体
     * @param request
     * @return
     * @throws IOException
     */
    public static String getRequestBody(HttpServletRequest request)  {
        ServletInputStream stream = null;
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer();
        try {
            stream = request.getInputStream();
            // 获取响应
            reader = new BufferedReader(new InputStreamReader(stream));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error("读取返回支付接口数据流出现异常！");
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
                log.error("关闭返回支付接口数据流出现异常！");
            }
        }
        return sb.toString();
    }
}
